package com.ham.mud.rooms;

import com.ham.mud.Colors;
import com.ham.mud.Runner;
import com.ham.mud.ServerConnection;
import com.ham.mud.characters.mobs.Mob;
import com.ham.mud.characters.mobs.MobService;
import com.ham.mud.characters.player.Player;
import com.ham.mud.configuration.FilePaths;
import com.ham.mud.items.Item;
import com.ham.mud.items.ItemService;

import java.io.*;
import java.util.*;

/**
 * Created by hlucas on Jun 16, 2011 at 2:04:03 PM
 */
public class RoomService {
    private static final Random rand = new Random();

    public static boolean hasCache = false;
    public static final String SPLITTER = "~";

    public static Map<String, Room> rooms = new HashMap<String, Room>();

    public static Room getRoom(String zone, int atX, int atY) {
        Room inMemory = rooms.get(zone + SPLITTER + atX + SPLITTER + atY);
        if (inMemory == null) {
            try {
                inMemory = loadRoom(zone, atX, atY);
            } catch (IOException e) {
                e.printStackTrace();
            }
            rooms.put(zone + SPLITTER + atX + SPLITTER + atY, inMemory);
            hasCache = true;
        }

        return inMemory;
    }

    //name
    //desc
    //exits
    //mobs
    //items

    private static Room loadRoom(String zone, int atX, int atY) throws IOException {
        File file = new File(FilePaths.getRoomFilePath(zone, atX, atY));
        if (!file.exists()) {
            Room room = new Room(zone, atX, atY, "Name", "Description", new String[]{}, new ArrayList<Mob>(), new ArrayList<Item>(), null, RoomType.PATH);
            saveRoom(room);
        }

        FileInputStream inputStream = new FileInputStream(file);

        DataInputStream in = new DataInputStream(inputStream);


        String name = in.readLine();
        String desc = in.readLine();
        String[] exits = in.readLine().split(" ");
        List<String> exitsList = new ArrayList<String>();
        for(String exit : exits) {
            exitsList.add(exit);
        }
        Collections.sort(exitsList);
        exits = exitsList.toArray(new String[exitsList.size()]);

        String[] mobNames = in.readLine().split(" ");
        String[] itemNames = in.readLine().split(" ");

        if (exits.length == 1) {
            if (exits[0].equals("") || exits[0].equals(" ")) {
                exits = new String[0];
            }
        }

        String ascii = in.readLine();
        if(ascii.equals("")) ascii = null;
        RoomType roomType = RoomType.valueOf(in.readLine());

        in.close();
        inputStream.close();

        List<Mob> mobs = MobService.getMobs(zone, mobNames);
        List<Item> items = ItemService.getItems(itemNames);

        return new Room(zone, atX, atY, name, desc, exits, mobs, items, ascii, roomType);
    }

    public static boolean roomExists(String zone, int atX, int atY) {
        File file = new File(FilePaths.getRoomFilePath(zone, atX, atY));
        return file.exists();
    }

    private static void saveRoom(Room room) throws IOException {
        File file = new File(FilePaths.getRoomFilePath(room.getZone(), room.getAtX(), room.getAtY()));
        if (!file.exists()) {
            try {
            file.createNewFile();
            } catch(IOException e) {
                //this zone doesn't exist;
                e.printStackTrace();
                //todo:add create zone support
            }
        }

        FileWriter fw = new FileWriter(file);
        BufferedWriter out = new BufferedWriter(fw);

        out.write(room.getName() + Colors.NEW_LINE);
        out.write(room.getDescription() + Colors.NEW_LINE);

        String[] exits = room.getExits();
        for (int i = 0; i < exits.length; i++) {
            out.write(exits[i]);
            if (i != exits.length - 1) {
                out.write(" ");
            }
        }
        out.write(Colors.NEW_LINE);

        List<Mob> mobs = room.getMobs();
        for (int i = 0; i < mobs.size(); i++) {
            out.write(mobs.get(i).getFileName());
            if (i != mobs.size() - 1) {
                out.write(" ");
            }
        }
        out.write(Colors.NEW_LINE);

        List<Item> items = room.getItems();
        for (int i = 0; i < items.size(); i++) {
            out.write(items.get(i).getFileName());
            if (i != items.size() - 1) {
                out.write(" ");
            }
        }
        out.write(Colors.NEW_LINE);

        if(room.getAscii() != null) {
            out.write(room.getAscii() + Colors.NEW_LINE);
        }

        out.write(Colors.NEW_LINE);
        out.write(room.getType().toString());

        out.close();
        fw.close();
    }


    public static void updateTitle(Room room, String line) {
        room.setName(line);
        try {
            saveRoom(room);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void updateDescription(Room room, String line) {
        room.setDescription(line);
        try {
            saveRoom(room);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void addItem(Room room, String itemName) {
        room.addItem(ItemService.getItem(itemName));
        try {
            saveRoom(room);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void removeItem(Room room, String itemName) {
        room.removeItem(ItemService.getItem(itemName));
        try {
            saveRoom(room);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void addMob(Room room, String mobName) {
        room.addMob(MobService.getMob(room.getZone(), mobName));
        try {
            saveRoom(room);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void removeMob(Room room, String mobName) {
        room.removeMob(mobName);
        try {
            saveRoom(room);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void addExit(Room room, String exit) {
        String[] exits = room.getExits();
        String[] newExits = new String[exits.length + 1];
        if (exits.length > 0) {
            System.arraycopy(exits, 0, newExits, 0, exits.length);
        }

        newExits[newExits.length - 1] = exit;
        room.setExits(newExits);
        try {
            saveRoom(room);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void removeExit(Room room, String exit) {
        String[] exits = room.getExits();
        String[] newExits = new String[exits.length - 1];
        int j = 0;
        for (int i = 0; i < exits.length; i++) {
            if (!exits[i].equals(exit)) {
                newExits[j] = exits[i];
                j++;
            }
        }
        room.setExits(newExits);
        try {
            saveRoom(room);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static boolean clearCache() {
        if (hasCache) {
            rooms.clear();
            List<ServerConnection> activeConnections = Runner.STATIC_INSTANCE.getConnections();
            for (ServerConnection conn : activeConnections) {
                Player player = conn.getPlayer();
                if (player != null) {
                    Room room = RoomService.getRoom(player.getZone(), player.getAtX(), player.getAtY());
                    room.addPlayer(conn, null);
                }
            }
            hasCache = false;
            return true;
        }

        return false;
    }

    public static String getExitString(int x, int y) {
        switch (x) {
            case -1:
                switch (y) {
                    case -1:
                        return "southwest";
                    case 0:
                        return "west";
                    case 1:
                        return "northwest";
                }
            case 0:
                switch (y) {
                    case -1:
                        return "south";
                    case 1:
                        return "north";
                }
            case 1:
                switch (y) {
                    case -1:
                        return "southeast";
                    case 0:
                        return "east";
                    case 1:
                        return "northeast";
                }
        }

        return null;
    }

    public static Room getRoom(Player player) {
        return getRoom(player.getZone(), player.getAtX(), player.getAtY());
    }

    public static Room getRoom(ServerConnection connection) {
        return getRoom(connection.getPlayer());
    }

    public static Room getRandomRoom() {
        File zonesDir = new File(FilePaths.getZonesFilePath());
        File[] zones = zonesDir.listFiles();
        File randZone = zones[rand.nextInt(zones.length)];
        if(randZone.getName().startsWith(".")) return getRandomRoom();  //stupid .svn directory
        File roomsDir = new File(randZone.getAbsolutePath() + File.separator + "rooms");
        File[] rooms = roomsDir.listFiles();
        File randRoom = rooms[rand.nextInt(rooms.length)];
        if(randRoom.isDirectory()) return getRandomRoom(); //stupid .svn directory
        String roomName = randRoom.getName();
        String[] roomNameSplit = roomName.split("\\.")[0].split("~");
        try {
            return RoomService.getRoom(randZone.getName(), Integer.valueOf(roomNameSplit[0]), Integer.valueOf(roomNameSplit[1]));
        } catch(NumberFormatException nfe) {
            nfe.printStackTrace();
            System.out.println(randZone.getName() + " "  + roomName);
            return getRandomRoom();
        }
    }

    public static Zone getZone(String zoneName) {
        try {
            return loadZone(zoneName);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private static Zone loadZone(String zoneName) throws IOException {
        File file = new File(FilePaths.getZoneFilePath(zoneName));

        FileInputStream inputStream = new FileInputStream(file);
        DataInputStream in = new DataInputStream(inputStream);

        String fullName = in.readLine();
        String[] levels = in.readLine().split(" ");

        return new Zone(zoneName, fullName, Integer.valueOf(levels[0]), Integer.valueOf(levels[1]));
    }
}
